package com.lins.websocket;

import cn.hutool.captcha.generator.RandomGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 服务端主动通知给用户
 * @Author linshuo
 * @Date 2023/2/1 16:32
 */
@Slf4j
@Component
@ServerEndpoint(value = "/ws",configurator = WsConfig.class)
public class WsServer {

    //集合存放所有的在线客户端
    public static final Map<String, Session> clients = new ConcurrentHashMap<>();

    //javax.servlet.http.HttpSession
    String sessionId = null;
    public static final Map<String, String> sessionIds = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session,EndpointConfig config){
        //这个config来自WsConfig的配置，里面包含httpSession对象，Key是httpSession的name
//        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());

        //获取当前httpSession的用户属性
        Map<String, Object> map = config.getUserProperties();
        String name = HttpSession.class.getName();
        HttpSession httpSession = null;
        //可能有的请求里没有javax.servlet.http.HttpSession
        if (map.containsKey(name)){
            httpSession = (HttpSession)map.get(name);
            sessionId = httpSession.getId();
        }else {
            sessionId = new RandomGenerator("0123456789", 6).generate();
        }

        //我们以httpSessionId为wsMap的key
        if (clients.containsKey(sessionId)) {
            log.info(httpSession.getAttribute("username")+" 已经连接");
            return;
        }
        //websocket的session不设置超时时间
        session.setMaxIdleTimeout(0);
        clients.put(sessionId,session);
        log.info("client:{}连接成功，在线人数：{}",sessionId,clients.size());
        //为了在OnClose时能找到这个sessionId，然后移除session，我们把sessionId存起来
        sessionIds.put(session.getId(),sessionId);
    }

    @OnClose
    public void OnClose(Session session){
        //当有多个ws连接时，防止sessionId变量被后来连接者覆盖，导致的不能准确移除session
        sessionId = sessionIds.get(session.getId());
        if (!clients.containsKey(sessionId)) {
            log.warn("没有{}对应的session连接，无需断开{}号session",sessionId,session.getId());
            return;
        }
        //移除websocket session
        clients.remove(sessionId);
        log.info("连接断开，在线人数："+clients.size());
        /**
         * session都不在了，我们维护的sessionId也一并移除。
         * 内部业务代码统一是用sessionId，但ws用的是session，所以我们使用sessionId来匹配session,
         * 当多个用户有多个sessionId时，sessionId也需要通过ws的session.getId()来匹配。
         * {sessionId:session},{session.getId():sessionID}
         **/
        sessionIds.remove(session.getId());
    }

    @OnError
    public void OnError(Session session,Throwable throwable) {
        log.error("websocket发生错误：{}",session.getId());
        throwable.printStackTrace();
    }

    /**
     * 客户端发来的消息
     **/
    @OnMessage
    public void onMessage(String message,Session session){
       log.info("收到客户端{}发来的消息：{}",session.getId(),message);
    }

    /**
     * 给别人发消息时调用
     * @param sessionId
     * @param message
     */
    public void sendMessage(String sessionId,String message){
        if (!clients.containsKey(sessionId)) {
            log.warn("未找到{}客户端的连接信息",sessionId);
            return;
        }
        Session session = clients.get(sessionId);
        try {
            session.getBasicRemote().sendText("server："+message);
            log.info("向client{}发送消息：{}",session.getId(),message);
        } catch (Exception e) {
            log.error("发送消息失败：{}",e);
            e.printStackTrace();
        }
    }


    //
}
